﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;

namespace DevOnServer
{
    public class CCharServer
    {
        public bool init(CNetwork network, CDatabase database)
        {
            m_database = database;

            Hashtable section = (Hashtable)ConfigurationManager.GetSection("Char");

            m_acceptor = network.createAcceptor(Convert.ToInt32(section["port"]));

            if (m_acceptor == null)
            {
                Console.WriteLine("CharServer port {0} can't be used !", section["port"]);
                return false;
            }

            section = (Hashtable)ConfigurationManager.GetSection("Channel");
            m_channelIp = (string)section["ip"];

            return _loadStartItems();
        }

        private bool _loadStartItems()
        {
            CFileReader file = new CFileReader();

            if (!file.load("Data/StartItems.inc"))
                return false;

            CStartItem item;
            byte currentSex = 2;
            string buff;

            while (!file.end)
            {
                buff = file.getString();

                if (buff == "ITEM")
                {
                    item = new CStartItem();
                    item.Sex = currentSex;
                    item.Place = file.getInt();
                    item.ID = file.getInt();
                    item.Count = file.getInt();
                    m_startItems.Add(item);
                }
                else if (buff == "SEX")
                {
                    buff = file.getString();

                    if (buff == "MALE")
                        currentSex = 0;
                    else if (buff == "FEMALE")
                        currentSex = 1;
                    else if (buff == "ALL" || buff == "SEXLESS" || buff == "NONE")
                        currentSex = 2;
                }
            }

            return true;
        }

        public bool run()
        {
            while (m_acceptor.NewClients.Count > 0)
            {
                CCharPlayer player = _createPlayer(m_acceptor.NewClients.Dequeue());
                player.Client.send(CPacketCreator.greeting(player.ID));
            }

            for (int i = m_players.Count - 1; i >= 0; i--)
            {
                if (!m_players[i].Client.Connected)
                {
                    m_players[i].Client.Free = true;
                    m_players.RemoveAt(i);
                }
                else if (m_players[i].Client.Incomming.Lenght > 0)
                {
                    while (_handlePacket(m_players[i])) ;

                    m_players[i].Client.Incomming.clear();
                }
            }

            return true;
        }

        private bool _handlePacket(CCharPlayer player)
        {
            CPacket packet = player.Client.Incomming;

            if (packet.readByte() != 0x5e)
                return false;

            packet.move(4);
            if (packet.readInt() > packet.Lenght - 13)
                return false;

            packet.move(8);
            switch (packet.readInt())
            {
                case 0xf6:
                    _cmdHandler_CharList(player);
                    return false;

                case 0xf5:
                    _cmdHandler_DeleteChar(player);
                    return false;

                case 0xf4:
                    _cmdHandler_CreateChar(player);
                    return false;

                case 0xff05:
                    _cmdHandler_EnterWorld(player);
                    return false;

                case 0x0b:
                case 0x14:
                    packet.move(4);
                    break;
            }

            return !packet.End;
        }

        private void _cmdHandler_EnterWorld(CCharPlayer player)
        {
            if (player.Account == null)
                return;

            CPacket packet = player.Client.Incomming;

            packet.move(packet.readInt()); // username

            int charId = packet.readInt();

            for (int i = 0; i < 3; i++)
            {
                if (player.Characters[i] != null && player.Characters[i].ID == charId)
                {
                    player.Client.send(CPacketCreator.worldConfirmation(player, i));
                    return;
                }
            }
        }

        private void _cmdHandler_DeleteChar(CCharPlayer player)
        {
            if (player.Account == null)
                return;

            CPacket packet = player.Client.Incomming;

            packet.move(packet.readInt()); // username
            packet.move(packet.readInt()); // password

            string password = packet.readString();

            if (player.Account.Password != password)
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.WrongPasswordToDelChar));
                return;
            }

            int charId = packet.readInt();

            m_database.deleteCharacter(player, charId);
            player.Client.send(CPacketCreator.charList(player));
        }

        private void _cmdHandler_CreateChar(CCharPlayer player)
        {
            if (player.Account == null)
                return;

            CPacket packet = player.Client.Incomming;

            packet.move(packet.readInt()); // username
            packet.move(packet.readInt()); // password

            byte place = packet.readByte();
            if (place < 0 || place > 2 || player.Characters[place] != null)
                return;

            string charName = packet.readString();
            if (charName.Length < 4 || charName.Length > 16)
                return;

            if (m_database.characterExists(charName))
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.NameInUse));
                return;
            }

            packet.move(3);

            byte hair = packet.readByte();
            int hairColor = packet.readInt();

            byte sex = packet.readByte();
            if (sex < 0 || sex > 1)
                return;

            int job = packet.readByte();
            byte head = packet.readByte();
            int bankPass = packet.readInt();

            CCharCharacter character = m_database.createCharacter(player, place, charName, hair, hairColor, sex, head, bankPass);
            if (character != null)
            {
                foreach (CStartItem item in m_startItems)
                    if (item.Sex == 2 || item.Sex == character.Sex)
                        m_database.createStartItem(character, item);
            }

            player.Client.send(CPacketCreator.charList(player));
        }

        private void _cmdHandler_CharList(CCharPlayer player)
        {
            CPacket packet = player.Client.Incomming;

            packet.move(packet.readInt()); // neuzVersion

            packet.readInt();

            string username = packet.readString();
            string password = packet.readString();

            CAccount account = m_database.getAccount(username);

            if (account == null
                || account.Password != password
                || account.AccessLevel == 0
                || account.BanTime >= CTime.seconds())
                return;

            player.Account = account;
            m_database.loadCharacters(player);

            player.Client.send(CPacketCreator.channelIp(m_channelIp));
            player.Client.send(CPacketCreator.charList(player));
        }

        private CCharPlayer _createPlayer(CNetClient client)
        {
            CCharPlayer player = new CCharPlayer();

            m_nextPlayerId++;

            player.ID = m_nextPlayerId;
            player.Client = client;

            m_players.Add(player);
            return player;
        }

        private CNetAcceptor m_acceptor;

        private List<CCharPlayer> m_players = new List<CCharPlayer>();

        private List<CStartItem> m_startItems = new List<CStartItem>();

        private int m_nextPlayerId;

        private string m_channelIp;

        private CDatabase m_database;
    }
}